package eu.fritschi.parachatcapture;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.BlockingQueue;

import jpcap.PacketReceiver;
import jpcap.packet.Packet;

import org.apache.log4j.Logger;

public class ParachatCapturePacketReceiver implements PacketReceiver {
	private static final Logger logger = Logger.getLogger(ParachatCapturePacketReceiver.class);
	private static final byte[] NEWLINEASBYTES = System.getProperty("line.separator").getBytes();
	
	private final BlockingQueue<ParachatMessage> messageQueue;
	private final Settings settings = Settings.getInstance();
	private final Object dumpFileLock = new Object();
	
	private FileOutputStream dumpFileOutputStream;
	private SimpleDateFormat sdf;
	
	public ParachatCapturePacketReceiver(BlockingQueue<ParachatMessage> messageQueue, File dumpFile) {
		this.messageQueue = messageQueue;
			if (dumpFile == null) {
				dumpFileOutputStream = null;
			} else {
				try {
					dumpFileOutputStream = new FileOutputStream(dumpFile, true);
					logger.info("Opened packet dump file for writing: " + dumpFile);
					sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
				} catch (IOException e) {
					logger.error("Cannot write to packet dumpfile.", e);
					dumpFileOutputStream = null;
					sdf = null;
				}
			}
	}
	
	@Override
	public void receivePacket(Packet packet) {
		// Write the packet to the file if a writer is available.
		synchronized (dumpFileLock) {
			if (dumpFileOutputStream != null) {
				try {
					dumpFileOutputStream.write(sdf.format(new Date()).getBytes());
					dumpFileOutputStream.write(NEWLINEASBYTES);
					dumpFileOutputStream.write(packet.data);
					dumpFileOutputStream.write(NEWLINEASBYTES);
				} catch (IOException e) {
					logger.error("Error caught while trying to wirte packet dump.", e);
				}
			}
		}
		List<ParachatMessage> parachatMessages = ParachatMessageFilter.filterPacket(packet.data);
		if (parachatMessages != null) {
			for (ParachatMessage parachatMessage : parachatMessages) {
				logger.info(parachatMessage);
				if (settings.processMessage(parachatMessage)) {
					messageQueue.add(parachatMessage);
				}				
			}
		}
	}
	
	public void freeResources() {
		synchronized (dumpFileLock) {
			if (dumpFileOutputStream != null) {
				try {
					logger.info("Closing dump file ...");
					dumpFileOutputStream.close();
					logger.info("Dump file has been closed.");
				} catch (IOException e) {
					logger.error("Failed to close the packet dump FileWriter.", e);
				}
				dumpFileOutputStream = null;
			}
		}
	}
}

